Skip to content

join: 1.37x faster on paired input, 2.5x faster than GNU, by skipping the locale compare - #14213

Merged
cakebaker merged 1 commit into
uutils:mainfrom
sylvestre:join-check-order-perf
Aug 29, 2026
Merged

join: 1.37x faster on paired input, 2.5x faster than GNU, by skipping the locale compare#14213
cakebaker merged 1 commit into
uutils:mainfrom
sylvestre:join-check-order-perf

Conversation

@sylvestre

Copy link
Copy Markdown
Contributor

In the default check-order mode the ordering warning is only emitted once unpaired lines have been seen (has_unpaired=true). Calling input.compare() (which may invoke ICU locale_cmp) on every line regardless was wasteful: on a 1M-line file with a locale active this accounts for ~35% of the total runtime.

Early-return before the compare() call when the result cannot possibly trigger a warning.

Benchmarks (fr_FR.UTF-8, 1M lines)

Time vs GNU
Before 814 ms 1.90x slower
After 523 ms 1.25x slower

GNU join: ~432 ms

The existing join_french_locale and join_unicode_locale CodSpeed benchmarks cover this path.

In the default check-order mode the ordering warning is only emitted
once unpaired lines have been seen (has_unpaired=true). Calling
input.compare() (which may invoke ICU locale_cmp) on every line
regardless was wasteful: on a 1M-line file with a locale active this
accounts for ~35% of the total runtime.

Early-return before the compare() call when the result cannot
possibly trigger a warning. Benchmarks (fr_FR.UTF-8, 1M lines):

  Before: 814 ms  (1.90x slower than GNU join)
  After:  523 ms  (1.25x slower than GNU join)
Copilot AI lite review requested due to automatic review settings August 28, 2026 17:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codspeed-hq

codspeed-hq Bot commented Aug 28, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 4.34%

⚡ 4 improved benchmarks
✅ 6 untouched benchmarks
⏩ 402 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation join_unicode_locale 2.7 ms 2.6 ms +4.55%
Simulation join_custom_separator 27 ms 25.9 ms +4.33%
Simulation join_french_locale 27.8 ms 26.7 ms +4.24%
Simulation join_full_match 27.8 ms 26.7 ms +4.23%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing sylvestre:join-check-order-perf (db1c69e) with main (d6aed5a)2

Open in CodSpeed

Footnotes

  1. 402 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (0688eff) during the generation of this report, so d6aed5a was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@github-actions

Copy link
Copy Markdown

GNU testsuite comparison:

GNU test failed: tests/head/head-write-error. tests/head/head-write-error is passing on 'main'. Maybe you have to rebase?
Note: The gnu test tests/csplit/csplit-heap is now being skipped but was previously passing.

@sylvestre

sylvestre commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

hyperfine results

1M-line inputs, release builds, hyperfine -N -w 3. GNU = coreutils 9.11.64.

Fully paired (1M x 1M), fr_FR.UTF-8

Command Mean [ms] Min [ms] Max [ms] Relative
before (fr_FR.UTF-8) 650.9 ± 7.1 640.3 664.8 1.37 ± 0.02
after (fr_FR.UTF-8) 473.9 ± 6.3 464.6 487.3 1.00
GNU 9.11.64 (fr_FR.UTF-8) 1175.1 ± 18.7 1151.1 1204.4 2.48 ± 0.05

Fully paired (1M x 1M), LC_ALL=C

Command Mean [ms] Min [ms] Max [ms] Relative
before (LC_ALL=C) 277.8 ± 6.0 272.1 291.7 1.08 ± 0.07
after (LC_ALL=C) 258.3 ± 15.0 215.4 273.6 1.00
GNU 9.11.64 (LC_ALL=C) 976.9 ± 10.2 964.0 992.1 3.78 ± 0.22

Half unpaired (1M x 500k), fr_FR.UTF-8

Command Mean [ms] Min [ms] Max [ms] Relative
before (fr_FR.UTF-8) 492.7 ± 7.8 481.3 504.4 1.00
after (fr_FR.UTF-8) 497.5 ± 8.3 486.7 514.5 1.01 ± 0.02
GNU 9.11.64 (fr_FR.UTF-8) 1125.0 ± 15.4 1110.1 1155.4 2.28 ± 0.05

@sylvestre sylvestre changed the title join: skip locale comparison in check_order default mode join: 1.37x faster on paired input, 2.5x faster than GNU, by skipping the locale compare Aug 29, 2026
@cakebaker
cakebaker merged commit 2a157be into uutils:main Aug 29, 2026
142 of 144 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants